#include "ocrorast.h"

void ColorEncodeLayout::encode_textlines(){
    int color;
    int column_num = 0x00010000;
    makelike(outputImage,inputImage);
    //Comment out this loop when the input image is not inverted
    for(int i = 0, l = outputImage.length1d(); i<l; i++){
        if(!inputImage.at1d(i))
            inputImage.at1d(i) = 0xff;
        else
            inputImage.at1d(i) = 0;
    }
    for(int i = 0, l = outputImage.length1d(); i<l; i++){
        if(!inputImage.at1d(i))
            outputImage.at1d(i) = 0;
        else
            outputImage.at1d(i) = 0x00ffffff;
    }
    color = 1;
    // Limit the number of text columns to what can actually be encoded (30)
    int MAX_COLS = 30;
    ASSERTWARN(textcolumns.length()<=MAX_COLS);
    int num_cols = (textcolumns.length() < MAX_COLS)?textcolumns.length():MAX_COLS;
    if(num_cols!=textcolumns.length()) {
        fprintf(stderr,"\nWarning: Too many text columns: %d\n", textcolumns.length());
        fprintf(stderr,"         Max # of text columns: %d\n\n", MAX_COLS);
    }
    for(int i = 0, l = textlines.length(); i<l; i++){
        bool changed = false;
        rectangle r = textlines[i];
        int j;
        for(j = 0; j<num_cols; j++)
            if(textcolumns[j].includes(r))
                break;
        column_num = (j+1)<<16;
        for(int x = r.x0, x1 = r.x1; x<x1; x++){
            for(int y = r.y0, y1 = r.y1; y<y1; y++){
                if(all) {
                    outputImage(x,y) = (color|column_num);
                    changed = true;
                } else if(!inputImage(x,y) && !outputImage(x,y)) {
                    outputImage(x,y) = (color|column_num);
                    changed = true;
                }
            }
        }
        if(changed)
            color++;
    }

}

void ColorEncodeLayout::encode_gutters(){
    for(int i=0, l=gutters.length(); i<l; i++){
        rectangle r = gutters[i];
        for(int x = r.x0, x1 = r.x1; x<x1; x++){
            for(int y = r.y0, y1 = r.y1; y<y1; y++){
                if(inputImage(x,y))
                    outputImage(x,y) = GUTTER_COLOR;
            }
        }
    }
}

void ColorEncodeLayout::encode_zones(rectarray &zones, int zone_color){
    sort_boxes_by_y0(zones);
    narray<bool> used;
    makelike(used,zones);
    fill(used,false);

    int num_cols = textcolumns.length();

    // First encode zones that belong to a single column and mark them
    for(int i=0; i<num_cols; i++){
        // Go through zones list in reverse order since they are sorted
        // w.r.t. image bottom
        int zone_num = 0;
        int column_num = i+1;
        for(int j=zones.length()-1; j>=0; j--){
            if(zones[j].fraction_covered_by(textcolumns[i]) >= 0.8){
                used[j] = true;
                zone_num++;
                rectangle r = zones[j];
                int zone_col = (column_num<<16) | zone_color | zone_num;
                for(int x = r.x0, x1 = r.x1; x<x1; x++){
                    for(int y = r.y0, y1 = r.y1; y<y1; y++){
                        if(all||!inputImage(x,y)) if(!outputImage(x,y))
                            outputImage(x,y) = zone_col;
                    }
                }

            }
        }
    }

    // All unmarked zones do not belong to a single column so label them
    // as multi-column elements
    int n_multicol_zones = 0;
    for(int i=0; i<zones.length(); i++){
        if(!used[i]){
            rectangle r = zones[i];
            n_multicol_zones++;
            int zone_col = MULTI_COLUMN_ELEMENT_COLOR |
                zone_color | n_multicol_zones ;
            for(int x = r.x0, x1 = r.x1; x<x1; x++){
                for(int y = r.y0, y1 = r.y1; y<y1; y++){
                    if(all||!inputImage(x,y)) if(!outputImage(x,y))
                        outputImage(x,y) = zone_col;
                }
            }
        }
    }
}

void ColorEncodeLayout::encode_images(){
    encode_zones(images, IMAGE_COLOR);
}

void ColorEncodeLayout::encode_graphics(){
    encode_zones(graphics, GRAPHICS_COLOR);
}

void ColorEncodeLayout::encode_rulings(){
    encode_zones(rulings, RULING_COLOR);
}

void ColorEncodeLayout::encode(){
    encode_textlines();
    encode_gutters();
    encode_images();
    encode_graphics();
    encode_rulings();
}

ColorEncodeLayout *make_ColorEncodeLayout(){
    return new ColorEncodeLayout();
}

